package vg.interfaces.ll_services.data_base_service.data.graph;

import com.google.common.collect.Lists;
import org.apache.commons.lang.Validate;
import vg.interfaces.ll_services.data_base_service.data.header.AttributeHeader;

import java.util.List;

/**
 * This class realizes something attribute.
 * Warning: No thread safety.
 *
 * @author Timur Zolotuhin (e-mail: tzolotuhin@gmail.com)
 */
public class Attribute extends SystemAttributeItem implements Cloneable {
	// Main data
	private String name = null;
	private Object value = null;
	private int type = AttributeHeader.NO_ATTRIBUTE_TYPE;
		
//=============================================================================
//-----------------Constructors------------------------------------------------
    private Attribute(String name, Object value, int type) {
        setName(name);

        this.value = value;
        this.type = type;
    }

    public Attribute(String name, String value, int type) {
        setName(name);
        if (!setValue(value, type))
            throw new IllegalArgumentException("Value isn't correct");
    }

    public Attribute(String name, Integer value) {
        this(name, (Object)value, AttributeHeader.INTEGER_ATTRIBUTE_TYPE);
    }

    public Attribute(String name, Float value) {
        this(name, (Object)value, AttributeHeader.DOUBLE_ATTRIBUTE_TYPE);
    }

    public Attribute(String name, Double value) {
        this(name, (Object)value, AttributeHeader.DOUBLE_ATTRIBUTE_TYPE);
    }

    public Attribute(String name, Boolean value) {
        this(name, (Object)value, AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE);
    }

    public Attribute(Attribute attribute) {
		super(attribute);

        if (attribute.name == null)
            throw new RuntimeException("Name can't be null");

        this.name = attribute.name;
		this.value = attribute.value;
		this.type = attribute.type;
	}	

//=============================================================================
//-----------------PUBLIC METHODS----------------------------------------------	
	public String getName() {
		return name;
	}

    public int getType() {
        return type;
    }

    /**
     * Returns string value, if type is string, otherwise <b>null</b>
     */
    public String getStringValue() {
        if (type == AttributeHeader.STRING_ATTRIBUTE_TYPE)
            return (String)value;
        return null;
    }

    /**
     * Returns integer value, if type is integer, otherwise <b>null</b>
     */
    public Integer getIntegerValue() {
        if (type == AttributeHeader.INTEGER_ATTRIBUTE_TYPE)
            return (Integer)value;
        return null;
    }

    /**
     * Returns boolean value, if type is boolean, otherwise <b>null</b>
     */
    public Boolean getBooleanValue() {
        if (type == AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE)
            return (Boolean)value;
        return null;
    }

    /**
     * Returns double value, if type is double, otherwise <b>null</b>
     */
    public Double getDoubleValue() {
        if (type == AttributeHeader.DOUBLE_ATTRIBUTE_TYPE)
            return (Double)value;
        return null;
    }

    public Double getRealValue() {
        if (isIntegerType())
            return ((Integer)value).doubleValue();

        if (isDoubleType())
            return ((Double)value);
        return null;
    }

    public boolean isStringType() {
        return getType() == AttributeHeader.STRING_ATTRIBUTE_TYPE;
    }

    public boolean isBooleanType() {
        return getType() == AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE;
    }

    public boolean isIntegerType() {
        return getType() == AttributeHeader.INTEGER_ATTRIBUTE_TYPE;
    }

    public boolean isDoubleType() {
        return getType() == AttributeHeader.DOUBLE_ATTRIBUTE_TYPE;
    }

    public boolean isNullType() {
        return getType() == AttributeHeader.NO_ATTRIBUTE_TYPE;
    }

    public void setName(String name) {
        if (name == null)
            throw new RuntimeException("Name can't be null");

        this.name = name;
    }

    public boolean isRealType() {
        return isDoubleType() || isIntegerType();
    }

    public boolean setStringValue(String value) {
        if (value == null)
            return false;

        type = AttributeHeader.STRING_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setBooleanValue(Boolean value) {
        if (value == null)
            return false;

        type = AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setIntegerValue(Integer value) {
        if (value == null)
            return false;

        type = AttributeHeader.INTEGER_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setDoubleValue(Double value) {
        if (value == null)
            return false;

        type = AttributeHeader.DOUBLE_ATTRIBUTE_TYPE;
        this.value = value;
        return true;
    }

    public boolean setValue(String strValue, int type) {
        try {
            switch (type) {
                case AttributeHeader.BOOLEAN_ATTRIBUTE_TYPE:
                    return setBooleanValue(Boolean.valueOf(strValue));

                case AttributeHeader.DOUBLE_ATTRIBUTE_TYPE:
                    return setDoubleValue(Double.valueOf(strValue));

                case AttributeHeader.INTEGER_ATTRIBUTE_TYPE:
                    return setIntegerValue(Integer.valueOf(strValue));

                case AttributeHeader.STRING_ATTRIBUTE_TYPE:
                    return setStringValue(String.valueOf(strValue));

                default:
                    return false;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * Returns string value.
     */
    public String toStringValue() {
        if (value == null)
            return null;
        return value.toString();
    }

    /**
     * Returns string value.
     * If value equals null then returns empty string.
     */
    public String toNotNullStringValue() {
        if (value == null)
            return "";
        return value.toString();
    }

    @Override
	public int hashCode() {
		return getStorableId();
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj == this)
            return true;

        if (obj != null && obj instanceof Attribute) {
			Attribute anotherAttr = ((Attribute)obj);
			if (getStorableId() >= 0 && getStorableId() == anotherAttr.getStorableId())
				return true;

			if (name != null && anotherAttr.name != null &&
				name.hashCode() == anotherAttr.name.hashCode() &&
				name.equals(anotherAttr.name))
                return true;
		}		
		return false;
	}
	
	@Override
	public Attribute clone() {
		return new Attribute(this);
	}
}
